package de.realriot.ipsdroid.v1.beta;

import de.realriot.ipsdroid.v1.beta.R;
import de.realriot.libs.ipsjson.IPSException;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class IPSExRowAdapter extends BaseExpandableListAdapter {
	private Context parentContext;
	private ArrayList<JSONObject> listGroups = new ArrayList<JSONObject>();
	private List<List<JSONObject>> listElements = new ArrayList<List<JSONObject>>(0);
	private ArrayList<Hashtable<String, String>> valueCache = new ArrayList<Hashtable<String,String>>();
	private IPSListViewData ipslvData;

	/**
     * Constructor of this ExpandableRowAdapter-Class.
     * 
     * @param context Previous context.
     * @param ipslv IPS-ListView Dataobject.
     * @param jsonhost JSON-RPC connection object.
     */
	public IPSExRowAdapter(Context context,
			IPSListViewData ipslv)
	{
		parentContext = context;
		//ipshost = jsonhost;
		
		// Announce the ipslv object globally.
		ipslvData = ipslv;
		
		// Add categories to groupList.
		listGroups.addAll(ipslv.catObjList);
		// Add instances to groupList.
		listGroups.addAll(ipslv.insObjList);
		// Add scripts to groupList.
		listGroups.addAll(ipslv.scrObjList);
		// Add variables to groupList.
		listGroups.addAll(ipslv.varObjList);
		
		// Add childs for groups.
		Integer count = 0;
		for ( JSONObject group : listGroups )
		{
			listElements.add(new ArrayList<JSONObject>(0));
			
			for ( JSONObject child : ipslv.insChildObjList )
			{
				try {
					if ( child.getString("ParentID").equals(group.getString("ObjectID") ) )
						listElements.get(count).add(child);
				} catch (JSONException e) {
					showMessageBox("0", "", e.getMessage());
				}
			}
			count++;
		}
	}

	/**
     * Return the child at a given position (group / child).
     * 
     * @param groupPosition GroupPosition of the requested child.
     * @param childPosition ChildPosition of the requested child.
     * @return The requested child.
     */
	@Override
	public JSONObject getChild(int groupPosition, int childPosition) {
		return listElements.get(groupPosition).get(childPosition);
	}

	/**
     * Dummy function! Returns the given childPosition.
     */
	@Override
	public long getChildId(int groupPosition, int childPosition) {
		return childPosition;
	}

	/**
     * The overridden method handles the childview within the listview.
     */
	@Override
	public View getChildView(int groupPosition, int childPosition,
			boolean isLastChild, View convertView, ViewGroup parent) {

		RelativeLayout rowLayout = (RelativeLayout) LayoutInflater.from(parentContext)
		.inflate(R.layout.exlv_childrow, parent, false);
		
		// Get child-Object.
		JSONObject obj = getChild(groupPosition, childPosition);
		
		try {
			// Child is a category.
			if ( obj.get("ObjectType").equals(IPSObjectType.otCategory) )
			{
				ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_ChildIcon);
				objIcon.setImageResource(R.drawable.app_lvfolder);
				
				TextView objName = (TextView) rowLayout.findViewById(R.id.ExLV_ObjectName);
				objName.setText(obj.getString("ObjectName"));
			}
	
			// Child is an instance.
			if ( obj.get("ObjectType").equals(IPSObjectType.otInstance ) )
			{
				TextView objName = (TextView) rowLayout.findViewById(R.id.ExLV_ObjectName);
				objName.setText(obj.getString("ObjectName"));
			}
	
			// Child is a script.
			if ( obj.get("ObjectType").equals(IPSObjectType.otScript ) )
			{
				ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_ChildIcon);
				objIcon.setImageResource(R.drawable.app_lvscript);
				
				TextView objName = (TextView) rowLayout.findViewById(R.id.ExLV_ObjectName);
				objName.setText(obj.getString("ObjectName"));
			}
	
			// Child is a variable.
			if ( obj.get("ObjectType").equals(IPSObjectType.otVariable ) )
			{
				JSONObject var = ipslvData.getVariable(obj.getString("ObjectID"));
	
				JSONObject varp = null;
				if (! var.get("VariableCustomProfile").equals("") )
					varp = ipslvData.getVarProfile(var.getString("VariableCustomProfile"));
				else if (! var.get("VariableProfile").equals("") )
					varp = ipslvData.getVarProfile(var.getString("VariableProfile"));
				
				if ( varp != null )
				{
					// Check if we can display an icon which is given within
					// the variable profile.
					if (! varp.get("Icon").equals("") )
					{
						ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_ChildIcon);
						int resID = parentContext.getResources().getIdentifier(
								parentContext.getPackageName() + ":drawable/ips_" +
								varp.getString("Icon").toLowerCase(), null, null);
						if ( resID != 0 )
							objIcon.setImageResource(resID);
					}
				}
				
				// Display the value of the variable.
				TextView objName = (TextView) rowLayout.findViewById(R.id.ExLV_ObjectName);
				objName.setText(obj.getString("ObjectName"));
				
				TextView objValue = (TextView) rowLayout.findViewById(R.id.ExLV_Value);
				objValue.setText(getIPSValue(var));
			}
		} catch (JSONException e) {
			showMessageBox("0", "Internal error", e.getMessage());
		} catch (IPSException e) {
			showMessageBox("0", "Internal error", e.getMessage());
		}
		return rowLayout;
	}

	/**
     * Returns the childcount of a given group.
     * 
     * @param groupPosition Position of the group.
     * @return The count of childelements of the group.
     */
	@Override
	public int getChildrenCount(int groupPosition) {
		return listElements.get(groupPosition).size();
	}

	/**
     * Return the group at a given position).
     * 
     * @param groupPosition Position of the group.
     * @return The requested group.
     */
	@Override
	public JSONObject getGroup(int groupPosition) {
		return listGroups.get(groupPosition);
	}

	/**
     * Return the count of groups within the listView.
     * 
     * @return Number of groups within the listView.
     */
	@Override
	public int getGroupCount() {
		return listGroups.size();
	}

	/**
     * Dummy function! Returns the given groupPosition.
     */
	@Override
	public long getGroupId(int groupPosition) {
		return groupPosition;
	}

	/**
     * This overridden method handles the groupview within the listview.
     */
	@Override
	public View getGroupView(int groupPosition, boolean isExpanded,
			View convertView, ViewGroup parent) {

		RelativeLayout rowLayout = (RelativeLayout) LayoutInflater.from(parentContext)
		.inflate(R.layout.exlv_grouprow, parent, false);
		
		JSONObject obj = getGroup(groupPosition);
		try {
			TextView objName = (TextView) rowLayout.findViewById(R.id.ExLV_GroupName);
			objName.setText(obj.getString("ObjectName"));
			
			// Check if we have to display an icon in front of the group.
			if ( getChildrenCount(groupPosition) > 0 )
			{
				ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_GroupIcon);
				objIcon.setImageResource(R.drawable.app_lvexpand);
			} else
			{
				ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_GroupIcon);
				objIcon.setImageResource(0);
			}
			
			// The group is a category.
			if ( obj.get("ObjectType").equals(IPSObjectType.otCategory) )
			{
				ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_GroupIcon);
				objIcon.setImageResource(R.drawable.app_lvfolder);
			}
			
			// The group is a script.
			if ( obj.get("ObjectType").equals(IPSObjectType.otScript ) )
			{
				ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_GroupIcon);
				objIcon.setImageResource(R.drawable.app_lvscript);
			}
			
			// The group is a variable.
			if ( obj.get("ObjectType").equals(IPSObjectType.otVariable ) )
			{
				JSONObject var = ipslvData.getVariable(obj.getString("ObjectID"));

				JSONObject varp = null;
				if (! var.get("VariableCustomProfile").equals("") )
					varp = ipslvData.getVarProfile(var.getString("VariableCustomProfile"));
				else if (! var.get("VariableProfile").equals("") )
					varp = ipslvData.getVarProfile(var.getString("VariableProfile"));
				
				if ( varp != null )
				{
					// Check if we can display an icon which is given within
					// the variable profile.
					if (! varp.get("Icon").equals("") )
					{
						ImageView objIcon = (ImageView) rowLayout.findViewById(R.id.ExLV_GroupIcon);
						int resID = parentContext.getResources().getIdentifier(
								parentContext.getPackageName() + ":drawable/ips_" +
								varp.getString("Icon").toLowerCase(), null, null);
						if ( resID != 0 )
							objIcon.setImageResource(resID);
					}
				}
				// Display the variable value.
				TextView objValue = (TextView) rowLayout.findViewById(R.id.ExLV_GroupValue);
				objValue.setText(getIPSValue(var));
			}
		} catch (JSONException e) {
			showMessageBox("0", "Internal error", e.getMessage());
		} catch (IPSException e) {
			showMessageBox("0", "Internal error", e.getMessage());
		}
		return rowLayout;
	}

	/**
     * Dummy function! Returns always TRUE.
     */
	@Override
	public boolean hasStableIds() {
		return true;
	}

	/**
     * Dummy function! Returns always TRUE.
     */
	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
		return true;
	}

	/**
     * Get the value of a variable. This function can cache valueData. So the
     * method looks within the cache first if it's already known. If not, it
     * will fetch the value from the ips-server.
     * 
     * @param id ID of the variable.
     * @param varType The variableType (Boolean, Float, ...).
     * @return The value of the variable.
	 * @throws JSONException 
	 * @throws IPSException 
     */
	public String getIPSValue(JSONObject var) throws JSONException, IPSException
	{
		String result = "";
		Boolean found = false;
		String id = var.getString("VariableID");
		
		// Check if we already have the value in our cache
		for ( int i = 0; i < valueCache.size(); i++ )
		{
			Hashtable<String, String> ht = valueCache.get(i);
			if ( ht.containsKey("id") )
			{
				if ( ht.get("id").equals(id) )
				{
					result = ht.get("value").toString();
					found = true;
				}
			}
		} 

		// If the value isn't cached, we will return a "pattern" value.
		if ( found == false )
			result = "???";
		
		return result;
	}

	/**
     * Clear the variable-value cache.
     */
	public void emptyValueCache()
	{
		valueCache.clear();
	}
	
	/**
	 * Sets the internal dataCache from the external valueWatcher thread.
	 */
	public void setDataCache(ArrayList<Hashtable<String, String>> dataCache)
	{
		valueCache = dataCache;
	}
	
	/**
	 * Returns the count of entries within the valueCache which is used
	 * by the valueWatcher thread. 
	 */
	public Integer getValueCount()
	{
		return valueCache.size();
	}

	/**
     * Shows an box with a given title and text.
     * The user has to acknowledge these message by
     * clicking the OK button. By given a mode the style
     * of the box will change.
     * - 0 ErrorBox
     * - 1 InfoBox
     * 
     * @param mode The mode of the messageBox
     * @param title Title of the messageBox
     * @param text Text to display 
     */
    public void showMessageBox(String mode, String title, String text)
	{
    	// ERRORBOX. Just a small error. No further action needed.
    	if ( mode.equals("0") )
    	{
    		AlertDialog.Builder msgBox;
    		msgBox = new AlertDialog.Builder(parentContext);
    		
    		msgBox.setIcon(R.drawable.app_problem);
    		msgBox.setTitle(title);
    		msgBox.setMessage(text);
    		msgBox.setPositiveButton("OK", null);

    		msgBox.create();
    		msgBox.show();
    	}
    	
    	// INFOBOX. This just an information box.
    	if ( mode.equals("1") )
    	{
    		AlertDialog.Builder msgBox;
    		msgBox = new AlertDialog.Builder(parentContext);
    		
    		msgBox.setIcon(R.drawable.app_problem);
    		msgBox.setTitle(title);
    		msgBox.setMessage(text);
    		msgBox.setPositiveButton("OK", null);

    		msgBox.create();
    		msgBox.show();
    	}
	}
}